package com.xinyue.framework.config;

import com.xinyue.framework.config.properties.PermitAllUrlProperties;
import com.xinyue.framework.security.filter.JwtAuthenticationTokenFilter;
import com.xinyue.framework.security.handle.AuthenticationEntryPointImpl;
import com.xinyue.framework.security.handle.LogoutSuccessHandlerImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.authentication.AuthenticationManager;
import org.springframework.security.authentication.ProviderManager;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configurers.AbstractHttpConfigurer;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.logout.LogoutFilter;
import org.springframework.web.filter.CorsFilter;

import java.util.List;

/**
 * spring security配置
 *
 * @author ruoyi
 */
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
@EnableWebSecurity
@Configuration
public class SecurityConfig {

    /**
     * 自定义用户认证逻辑
     */
    @Autowired
    private UserDetailsService userDetailsService;

    /**
     * 认证失败处理类
     */
    @Autowired
    private AuthenticationEntryPointImpl unauthorizedHandler;

    /**
     * 退出处理类
     */
    @Autowired
    private LogoutSuccessHandlerImpl logoutSuccessHandler;

    /**
     * token认证过滤器
     */
    @Autowired
    private JwtAuthenticationTokenFilter authenticationTokenFilter;

    /**
     * 跨域过滤器
     */
    @Autowired
    private CorsFilter corsFilter;

    /**
     * 允许匿名访问的地址
     */
    @Autowired
    private PermitAllUrlProperties permitAllUrl;

    @Bean
    public AuthenticationManager authenticationManager() {
        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        authenticationProvider.setUserDetailsService(userDetailsService);
        authenticationProvider.setPasswordEncoder(this.bCryptPasswordEncoder());

        return new ProviderManager(authenticationProvider);
    }

    @Bean
    public SecurityFilterChain securityFilterChain(HttpSecurity httpSecurity) throws Exception {
        // CSRF禁用，因为不使用session
        httpSecurity.csrf(AbstractHttpConfigurer::disable);
        // 禁用HTTP响应标头,表示响应信息不需要缓存
        httpSecurity.headers(h -> h.cacheControl(c -> c.disable()));
        httpSecurity.headers(h -> h.frameOptions(f -> f.disable()));
        // 认证失败处理类
        httpSecurity.exceptionHandling(e -> e.authenticationEntryPoint(unauthorizedHandler));
        httpSecurity.sessionManagement(s -> s.sessionCreationPolicy(SessionCreationPolicy.STATELESS));
        // 不需要认证的接口
        httpSecurity.authorizeHttpRequests(a -> {
            a.requestMatchers("/login", "/register", "/captchaImage","/profile/*").permitAll();
        });
        List<String> permitAllUrlUrls = permitAllUrl.getUrls();
        if (permitAllUrlUrls != null && !permitAllUrlUrls.isEmpty()) {
            String[] arrayUrls = permitAllUrlUrls.toArray(new String[0]);
            httpSecurity.authorizeHttpRequests(a -> a.requestMatchers(arrayUrls).permitAll());
        }
        // 不需要认证的静态页面访问
        httpSecurity.authorizeHttpRequests(a -> {
            a.requestMatchers(HttpMethod.GET, "/*.html", "/*/*.html", "/*/*.css", "/*/*.js", "/profile/*").permitAll();
        });
        // 不需要认证的swagger请求
        httpSecurity.authorizeHttpRequests(a -> {
            a.requestMatchers("/swagger-ui.html", "/v3/api-docs/*", "/swagger-resources/*", "/webjars/*", "/*/api-docs",
                "/druid/*").permitAll();
        });
        httpSecurity.authorizeHttpRequests(a -> a.anyRequest().authenticated());
        // 添加Logout filter
        httpSecurity.logout(f -> f.logoutUrl("/logout").logoutSuccessHandler(logoutSuccessHandler));
        // 添加JWT filter
        httpSecurity.addFilterBefore(authenticationTokenFilter, UsernamePasswordAuthenticationFilter.class);
        // 添加CORS filter
        httpSecurity.addFilterBefore(corsFilter, JwtAuthenticationTokenFilter.class);
        httpSecurity.addFilterBefore(corsFilter, LogoutFilter.class);
        return httpSecurity.build();
    }

    /**
     * 强散列哈希加密实现
     */
    @Bean
    public BCryptPasswordEncoder bCryptPasswordEncoder() {
        return new BCryptPasswordEncoder();
    }

}
